package io.cloud.tec.project.web;

import io.cloud.tec.project.constants.PdfConstant;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
import java.util.Objects;

@RestController
@RequestMapping(PdfConstant.PDF_WEB_URL_PREFIX)
public class PdfController {

    @RequestMapping(value = "preview")
    public void firefox(String pdf) {
        final ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        HttpServletResponse response = requestAttributes.getResponse();
        String path = ClassLoader.getSystemClassLoader().getResource("").getPath() + "public/" + pdf;
        try {
            // 下载的字节范围
            int startByte = 0, endByte = 0, totalByte, length;
            FileInputStream fis = new FileInputStream(path);
            // 文件总大小
            totalByte = fis.available();
            if (request != null && request.getHeader("range") != null) {
                // 断点续传
                String[] range = request.getHeader("range").replaceAll("[^0-9\\-]", "").split("-");
                // 下载起始位置
                startByte = Integer.parseInt(range[0]);
                // 下载结束位置
                if (range.length > 1) {
                    endByte = Integer.parseInt(range[1]);
                }
                // 返回http状态
                response.setStatus(HttpStatus.PARTIAL_CONTENT.value());
            } else {
                // 检查referer是否有效
                if (!checkRefererValid(request)) {
                    // 下载免责声明pdf
                    downloadDisclaimerPdf();
                    return;
                }
                endByte = totalByte - 1;
                response.setStatus(HttpStatus.PARTIAL_CONTENT.value());
            }
            startByte = Math.max(startByte, 0);
            endByte = Math.min(endByte, totalByte - 1);
            length = endByte - startByte + 1;
            //表明服务器支持分片加载
            response.setHeader(HttpHeaders.ACCEPT_RANGES, "bytes");
            //Content-Range: bytes 0-65535/408244，表明此次返回的文件范围
            response.setHeader(HttpHeaders.CONTENT_RANGE, "bytes " + startByte + "-" + endByte + "/" + totalByte);
            //需要设置此属性，否则浏览器默认不会读取到响应头中的Accept-Ranges属性，因此会认为服务器端不支持分片，所以会直接全文下载
            response.setHeader(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "Accept-Ranges,Content-Range");
            //告知浏览器这是一个字节流，浏览器处理字节流的默认方式就是下载
            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
            //表明该文件的所有字节大小
            response.setContentLength(length);
            // sendFile
            sendFile(fis, startByte, length, response.getOutputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void downloadDisclaimerPdf() throws IOException {
        final RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
        HttpServletResponse response = ((ServletRequestAttributes) requestAttributes).getResponse();
        String disclaimerPdfPath = ClassLoader.getSystemClassLoader().getResource("").getPath() + "public/mzsm.pdf";
        FileInputStream fileInputStream = new FileInputStream(disclaimerPdfPath);
        sendFile(fileInputStream, 0, fileInputStream.available(), response.getOutputStream());
    }

    private boolean checkRefererValid(HttpServletRequest request) throws UnsupportedEncodingException {
        // // http://localhost:8081/pdf.js/web/viewer.html?file=http://localhost:8081/pdf/firefox
        String referer = request.getHeader(HttpHeaders.REFERER);
        if (Objects.isNull(referer)) return false;
        referer = URLDecoder.decode(referer, StandardCharsets.UTF_8.name());
        return StringUtils.containsIgnoreCase(referer, request.getRequestURI());
    }

    private void sendFile(FileInputStream fis, long position, long count, OutputStream outputStream) throws IOException {
        final FileChannel channel = fis.getChannel();
        channel.transferTo(position, count, Channels.newChannel(outputStream));
        channel.close();
        fis.close();
    }
}
